<!DOCTYPE html>
<html lang="en" data-bs-theme="auto">
  <head>
    <%- header %>
    <style>
      .config-page {
        padding: 1em;
        border: 1px solid transparent;
        border-top: none;
      }

      .buttons {
        padding: 1em 0;
      }

      .ms-item {
        border: 1px solid;
        border-radius: 2px;
        font-size: 12px;
        font-weight: bold;
      }
    </style>
  </head>

  <body id="app" v-cloak>
    <Navbar></Navbar>
    <div class="container">
      <h1 class="my-4">{{ $t('config.configuration') }}</h1>
      <div class="form card" v-if="config">
        <!-- Header -->
        <ul class="nav nav-tabs">
          <li class="nav-item" v-for="tab in tabs" :key="tab.id">
            <a class="nav-link" :class="{'active': tab.id === currentTab}" href="#" @click="currentTab = tab.id"
              >{{tab.name}}</a
            >
          </li>
        </ul>

        <!-- General Tab -->
        <general
          v-if="currentTab === 'general'"
          :config="config"
          :global-prep-cmd="global_prep_cmd"
          :platform="platform"
        >
        </general>

        <!-- Input Tab -->
        <inputs v-if="currentTab === 'input'" :config="config" :platform="platform"> </inputs>

        <!-- Audio/Video Tab -->
        <audio-video
          v-if="currentTab === 'av'"
          :config="config"
          :platform="platform"
          :resolutions="resolutions"
          :fps="fps"
          :display_mode_remapping="display_mode_remapping"
        >
        </audio-video>

        <!-- Network Tab -->
        <network v-if="currentTab === 'network'" :config="config" :platform="platform"> </network>

        <!-- Files Tab -->
        <files v-if="currentTab === 'files'" :config="config" :platform="platform"> </files>

        <!-- Advanced Tab -->
        <advanced v-if="currentTab === 'advanced'" :config="config" :platform="platform"> </advanced>

        <container-encoders :current-tab="currentTab" :config="config" :platform="platform"> </container-encoders>
      </div>

      <!-- Save and Apply buttons -->
      <div class="alert alert-success my-4" v-if="saved && !restarted">
        <b>{{ $t('_common.success') }}</b> {{ $t('config.apply_note') }}
      </div>
      <div class="alert alert-success my-4" v-if="restarted">
        <b>{{ $t('_common.success') }}</b> {{ $t('config.restart_note') }}
      </div>
      <div class="mb-3 buttons">
        <button class="btn btn-primary" @click="save">{{ $t('_common.save') }}</button>
        <button class="btn btn-success" @click="apply" v-if="saved && !restarted">{{ $t('_common.apply') }}</button>
      </div>
    </div>
  </body>

  <script type="module">
    import { computed, createApp } from 'vue'
    import { initApp } from './init'
    import Navbar from './Navbar.vue'
    import General from './configs/tabs/General.vue'
    import Inputs from './configs/tabs/Inputs.vue'
    import Network from './configs/tabs/Network.vue'
    import Files from './configs/tabs/Files.vue'
    import Advanced from './configs/tabs/Advanced.vue'
    import AudioVideo from './configs/tabs/AudioVideo.vue'
    import ContainerEncoders from './configs/tabs/ContainerEncoders.vue'
    import { $tp, usePlatformI18n } from './platform-i18n'

    const app = createApp({
      components: {
        Navbar,
        General,
        Inputs,
        Network,
        Files,
        Advanced,
        // They will be accessible via audio-video, container-encoders only.
        AudioVideo,
        ContainerEncoders,
      },
      data() {
        return {
          platform: '',
          saved: false,
          restarted: false,
          config: null,
          fps: [],
          resolutions: [],
          currentTab: 'general',
          global_prep_cmd: [],
          display_mode_remapping: [],
          tabs: [
            // TODO: Move the options to each Component instead, encapsulate.
            {
              id: 'general',
              name: 'General',
              options: {
                locale: 'en',
                sunshine_name: '',
                min_log_level: 2,
                global_prep_cmd: '[]',
                notify_pre_releases: 'disabled',
              },
            },
            {
              id: 'input',
              name: 'Input',
              options: {
                controller: 'enabled',
                gamepad: 'auto',
                ds4_back_as_touchpad_click: 'enabled',
                motion_as_ds4: 'enabled',
                touchpad_as_ds4: 'enabled',
                back_button_timeout: -1,
                keyboard: 'enabled',
                key_repeat_delay: 500,
                key_repeat_frequency: 24.9,
                always_send_scancodes: 'enabled',
                key_rightalt_to_key_win: 'disabled',
                mouse: 'enabled',
                high_resolution_scrolling: 'enabled',
                native_pen_touch: 'enabled',
                keybindings: '[0x10,0xA0,0x11,0xA2,0x12,0xA4]', // todo: add this to UI
              },
            },
            {
              id: 'av',
              name: 'Audio/Video',
              options: {
                audio_sink: '',
                virtual_sink: '',
                install_steam_audio_drivers: 'enabled',
                adapter_name: '',
                output_name: '',
                display_device_prep: 'no_operation',
                resolution_change: 'automatic',
                manual_resolution: '',
                refresh_rate_change: 'automatic',
                manual_refresh_rate: '',
                hdr_prep: 'automatic',
                display_mode_remapping: '[]',
                resolutions: '[1280x720,1920x1080,2560x1080,2560x1440,2560x1600,3440x1440,3840x2160]',
                fps: '[60,90,120,144]',
                max_bitrate: 0,
              },
            },
            {
              id: 'network',
              name: 'Network',
              options: {
                upnp: 'disabled',
                address_family: 'ipv4',
                port: 47989,
                origin_web_ui_allowed: 'lan',
                external_ip: '',
                lan_encryption_mode: 0,
                wan_encryption_mode: 1,
                ping_timeout: 10000,
              },
            },
            {
              id: 'files',
              name: 'Config Files',
              options: {
                file_apps: '',
                credentials_file: '',
                log_path: '',
                pkey: '',
                cert: '',
                file_state: '',
              },
            },
            {
              id: 'advanced',
              name: 'Advanced',
              options: {
                fec_percentage: 20,
                qp: 28,
                min_threads: 2,
                hevc_mode: 0,
                av1_mode: 0,
                capture: '',
                encoder: '',
              },
            },
            {
              id: 'nv',
              name: 'NVIDIA NVENC Encoder',
              options: {
                nvenc_preset: 1,
                nvenc_twopass: 'quarter_res',
                nvenc_spatial_aq: 'disabled',
                nvenc_vbv_increase: 0,
                nvenc_realtime_hags: 'enabled',
                nvenc_split_encode: 'driver_decides',
                nvenc_latency_over_power: 'enabled',
                nvenc_opengl_vulkan_on_dxgi: 'enabled',
                nvenc_h264_cavlc: 'disabled',
              },
            },
            {
              id: 'qsv',
              name: 'Intel QuickSync Encoder',
              options: {
                qsv_preset: 'medium',
                qsv_coder: 'auto',
                qsv_slow_hevc: 'disabled',
              },
            },
            {
              id: 'amd',
              name: 'AMD AMF Encoder',
              options: {
                amd_usage: 'ultralowlatency',
                amd_rc: 'vbr_latency',
                amd_enforce_hrd: 'disabled',
                amd_quality: 'balanced',
                amd_preanalysis: 'disabled',
                amd_vbaq: 'enabled',
                amd_coder: 'auto',
              },
            },
            {
              id: 'vt',
              name: 'VideoToolbox Encoder',
              options: {
                vt_coder: 'auto',
                vt_software: 'auto',
                vt_realtime: 'enabled',
              },
            },
            {
              id: 'sw',
              name: 'Software Encoder',
              options: {
                sw_preset: 'superfast',
                sw_tune: 'zerolatency',
              },
            },
          ],
        }
      },
      provide() {
        return {
          platform: computed(() => this.platform),
        }
      },
      created() {
        fetch('/api/config')
          .then((r) => r.json())
          .then((r) => {
            // 使用映射表简化平台过滤逻辑
            const platformExclusions = {
              windows: ['vt', 'vaapi'],
              linux: ['amd', 'qsv', 'vt'],
              macos: ['amd', 'nv', 'qsv', 'vaapi'],
            }

            this.config = r
            this.platform = this.config.platform
            this.tabs = this.tabs.filter((tab) => !platformExclusions[this.platform]?.includes(tab.id))

            // remove values we don't want in the config file
            delete this.config.platform
            delete this.config.status
            delete this.config.version

            // TODO: let each tab's Component handle it's own data instead of doing it here

            // Populate default values from tabs options
            this.tabs.forEach((tab) => {
              Object.keys(tab.options).forEach((optionKey) => {
                if (this.config[optionKey] === undefined) {
                  this.config[optionKey] = tab.options[optionKey]
                }
              })
            })

            this.fps = JSON.parse(this.config.fps)
            // 优化分辨率解析逻辑
            try {
              this.resolutions = JSON.parse(this.config.resolutions.replace(/(\d+)x(\d+)/g, '"$1x$2"'))
            } catch (e) {
              console.error('Error parsing resolutions:', e)
              this.resolutions = []
            }

            this.config.global_prep_cmd = this.config.global_prep_cmd || []
            this.global_prep_cmd = JSON.parse(this.config.global_prep_cmd)

            this.config.display_mode_remapping = this.config.display_mode_remapping || []
            this.display_mode_remapping = JSON.parse(this.config.display_mode_remapping)
          })
      },
      methods: {
        forceUpdate() {
          this.$forceUpdate()
        },
        serialize() {
          const nl = this.config === 'windows' ? '\r\n' : '\n'
          this.config.resolutions = JSON.stringify(this.resolutions)
            .replace(/","/g, `,${nl}    `)
            .replace(/\["/, `[${nl}    `)
            .replace(/"\]/, `${nl}]`)

          this.fps = this.fps.filter((item) => +item >= 30 && +item <= 500)
          this.config.fps = JSON.stringify(this.fps).replaceAll('"', '')
          this.config.global_prep_cmd = JSON.stringify(this.global_prep_cmd)
          this.config.display_mode_remapping = JSON.stringify(this.display_mode_remapping)
        },
        async save() {
          this.saved = false
          this.restarted = false
          this.serialize()

          const config = JSON.parse(JSON.stringify(this.config))

          // 使用更清晰的默认值过滤逻辑
          this.tabs.forEach((tab) => {
            Object.keys(tab.options).forEach((optionKey) => {
              if (this.shouldDeleteDefault(config, tab, optionKey)) {
                delete config[optionKey]
              }
            })
          })

          try {
            const response = await fetch('/api/config', {
              method: 'POST',
              body: JSON.stringify(config),
            })
            this.saved = response.status === 200
            return this.saved
          } catch (error) {
            console.error('Save failed:', error)
            return false
          }
        },
        shouldDeleteDefault(config, tab, optionKey) {
          const excludedKeys = ['resolutions', 'fps', 'adapter_name']
          if (excludedKeys.includes(optionKey)) return false

          const currentValue = config[optionKey]
          const defaultValue = tab.options[optionKey]

          try {
            return JSON.stringify(JSON.parse(currentValue)) === JSON.stringify(JSON.parse(defaultValue))
          } catch {
            return String(currentValue) === String(defaultValue)
          }
        },
        apply() {
          this.saved = this.restarted = false
          let saved = this.save()

          saved.then((result) => {
            if (result === true) {
              this.restarted = true
              setTimeout(() => {
                this.saved = this.restarted = false
              }, 5000)
              fetch('/api/restart', {
                method: 'POST',
              })
            }
          })
        },
      },
      mounted() {
        // 优化哈希处理逻辑
        const handleHash = () => {
          const hash = window.location.hash.slice(1)
          if (!hash) return

          const targetTab = this.tabs.find((tab) => tab.id === hash || Object.keys(tab.options).includes(hash))

          if (targetTab) {
            this.currentTab = targetTab.id
            this.$nextTick(() => {
              const element = document.getElementById(hash)
              element?.scrollIntoView({ behavior: 'smooth' })
            })
          }
        }

        handleHash()
        window.addEventListener('hashchange', handleHash)
      },
    })

    initApp(app)
  </script>
</html>
